package nb.diskfilesystem;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

import java.awt.*;
import java.io.ByteArrayOutputStream;

public class FATManage {
    private static TableView<FAT_tableEntry> fatTable; // 用于存储 TableView 引用
    private static ObservableList<FAT_tableEntry> fatTableEntries; // 用于存储 FAT 表的数据

    // 检查父节点下的目录项是否有空闲位置
    public static int findFreeDirectoryEntry(Directory_Node parentNode) {
        int parentBlock = parentNode.getStartBlock();
        byte[] buffer = DiskManage.readBlock(parentBlock);    //把父节点对应的那一块字节都加载进来
        // 查找父节点目录项中的空闲位置
        for (int i = 0; i < 8; i++) {
            if (buffer[i * 8] == '$') {
                return i; // 返回空闲目录项的索引
            }
        }
        return -1; // 没有空闲目录项
    }

    //查询FAT表中空闲的字节（0表示空闲）。
    public static int searchFreeByte() {
        byte[] buffer = new byte[64];
        buffer = DiskManage.readBlock(0);
        for(int i = 3;i < 64;i++) {
            if(buffer[i] == 0) return (byte)i;
        }
        buffer = DiskManage.readBlock(1);
        for (int i = 0;i < 64;i++) {
            if(buffer[i] == 0) return (byte) (i + 64);
        }
        return -1;
    }

    //将FAT表中的某个字节设置为255，表示该字节已被占用。
    public static void setByteUsed(int index) {
        if (index >= 0 && index < 128) {
            //先处理前128个字节中的fat表
            if(index>=64){
                DiskManage.writeOnlyByte(1,(index-64)/8,index%8,(byte)255);
            }else{
                DiskManage.writeOnlyByte(0,index/8,index%8,(byte)255);
            }
            //对应的真正磁盘区域应该已经为0

            // 更新FAT表显示
            updateFATTable();
        }
    }

    //将FAT表中的某个字节设置为0，表示该字节未被占用。
    public static void setByteFree(int index) {
        if (index >= 0 && index < 128) {
            //先处理前128个字节中的fat表
            if(index>=64){
                DiskManage.writeOnlyByte(1,(index-64)/8,index%8,(byte)0);
            }else{
                DiskManage.writeOnlyByte(0,index/8,index%8,(byte)0);
            }
            //后处理真正的磁盘区域
            byte[] buffer = new byte[64];
            for (int i = 0; i < 64; i++)
            {
                buffer[i] = 0;
            }
            //把对应块的字节填充为0
            DiskManage.writeBlock(index,buffer);

            // 更新FAT表显示
            updateFATTable();
        }
    }

    //根据传入进来的文件磁盘起始块号来获得所有文件的内容
    public static  byte[] getFileContent(int startBolck){
        int next=startBolck;
        ByteArrayOutputStream result = new ByteArrayOutputStream(); // 用于存储合并后的字节数据
        while(true){
            if(next==-1){
                break;
            }
            if(next>=64){
                byte[] temp = DiskManage.readBlock(next);
                next=DiskManage.readOnlyByte(1,(next-64)/8,next%8);
                result.write(temp, 0, temp.length); // 将读取的块写入到result中
            }else{
                byte[] temp = DiskManage.readBlock(next);
                next=DiskManage.readOnlyByte(0,next/8,next%8);
                result.write(temp, 0, temp.length); // 将读取的块写入到result中
            }
        }
        return result.toByteArray();// 将结果转换为byte数组返回
    }

    //根据传入进来的文件磁盘起始块号来释放所有文件的内容置为0还有fat表也对应清空
    public static  void freeFileContent(int startBolck){
        int next=startBolck;
        byte[] buffer = new byte[64];//用于清空块的byte数组
        for (int i = 0; i < 64; i++)
        {
            buffer[i] = 0;
        }
        while(true){
            if(next==-1){
                break;
            }
            if(next>=64){
                DiskManage.writeBlock(next,buffer);   //把对应的块全部清空
                int temp=next;
                next=DiskManage.readOnlyByte(1,(next-64)/8,next%8);  //先读取下一块位置
                DiskManage.writeOnlyByte(1,(temp-64)/8,temp%8,(byte)0);//释放fat表中的对应块

            }else{
                DiskManage.writeBlock(next,buffer);   //把对应的块全部清空
                int temp=next;
                next=DiskManage.readOnlyByte(0,next/8,next%8);
                DiskManage.writeOnlyByte(0,temp/8,temp%8,(byte)0);//释放fat表中的对应块
            }
        }
    }

    //根据传入进来的文件内容也就是byte数组来填充到文件中还有fat表中，最后返回起始块号
    public static  int saveFileContent(byte[] content){
        int startBlock=FATManage.searchFreeByte();   //查询哪个位置是空闲的作为起始块位置
        int next=startBlock;
        int last=startBlock;
        int chunkSize = 64; // 每次处理的字节数

        for (int i = 0; i < content.length; i += chunkSize) {
            // 计算剩余字节数，以防最后一块不满64字节
            int remainingBytes = Math.min(chunkSize, content.length - i);
            System.out.println("这次要写入的字节数是："+remainingBytes);
            byte[] chunk = new byte[chunkSize]; // 固定大小64字节
            // 将剩余的字节数复制到 chunk 中
            System.arraycopy(content, i, chunk, 0, remainingBytes);
            // 如果不足64字节，填充剩余部分为0
            for (int j = remainingBytes; j < chunkSize; j++) {
                chunk[j] = 0; // 填充为0
            }
            //首先把这个字节数组存储到那个空闲的块
            DiskManage.writeBlock(next,chunk);
            //保存完成的块要标记为-1
            if(next>=64){
                DiskManage.writeOnlyByte(1,(next-64)/8,next%8,(byte)-1);//在fat表中写入下一块
            }else{
                DiskManage.writeOnlyByte(0,next/8,next%8,(byte)-1);//在fat表中中写入下一位置块
            }
            last=next;
            next=FATManage.searchFreeByte();   //注意searchFreeByte是根据fat表来的，所以应该立即更新fat表
            if(last>=64){
                DiskManage.writeOnlyByte(1,(last-64)/8,last%8,(byte)next);//在fat表中写入下一块
            }else{
                DiskManage.writeOnlyByte(0,last/8,last%8,(byte)next);//在fat表中中写入下一位置块
            }
        }
        //遍历出来之后next一定指向空闲块，last一定指向最后一个块
        if(last>=64){
            DiskManage.writeOnlyByte(1,(last-64)/8,last%8,(byte)-1);//最后一块的fat表设置为-1
        }else{
            DiskManage.writeOnlyByte(0,last/8,last%8,(byte)-1);//最后一块的fat表设置为-1
        }
        DiskManage.diskPrint();
        return startBlock;
    }






    // 初始化 FAT 表的 TableView
    public static void initFATTable(TableView<FAT_tableEntry> tableView) {
        fatTable = tableView;
        initTableColumns();
        fatTableEntries = FXCollections.observableArrayList();
        fatTable.setItems(fatTableEntries);
        fatTable.getStylesheets().add(FATManage.class.getResource("/nb/diskfilesystem/css/fatTable.css").toExternalForm());
        updateFATTable(); // 初始化时更新一次
    }

    // 初始化 TableView 的列
    private static void initTableColumns() {
        // 块号列
        TableColumn<FAT_tableEntry, Integer> blockNumberColumn = new TableColumn<>("块号");
        blockNumberColumn.setCellValueFactory(new PropertyValueFactory<>("blockNumber"));
        blockNumberColumn.setStyle("-fx-alignment: CENTER;"); // 居中对齐

        // 状态列
        TableColumn<FAT_tableEntry, Integer> statusColumn = new TableColumn<>("状态");
        statusColumn.setCellValueFactory(new PropertyValueFactory<>("status"));
        statusColumn.setStyle("-fx-alignment: CENTER;"); // 居中对齐

        // 文件类型列
        TableColumn<FAT_tableEntry, String> fileTypeColumn = new TableColumn<>("文件类型");
        fileTypeColumn.setCellValueFactory(new PropertyValueFactory<>("fileType"));
        fileTypeColumn.setStyle("-fx-alignment: CENTER;"); // 居中对齐

        // 文件名字列
        TableColumn<FAT_tableEntry, String> fileNameColumn = new TableColumn<>("文件名字");
        fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
        fileNameColumn.setStyle("-fx-alignment: CENTER;"); // 居中对齐

        // 添加所有列到表格
        fatTable.getColumns().addAll(blockNumberColumn, statusColumn, fileTypeColumn, fileNameColumn);

        // 设置列宽自适应
        blockNumberColumn.prefWidthProperty().bind(fatTable.widthProperty().multiply(0.2)); // 20%宽度
        statusColumn.prefWidthProperty().bind(fatTable.widthProperty().multiply(0.2)); // 20%宽度
        fileTypeColumn.prefWidthProperty().bind(fatTable.widthProperty().multiply(0.3)); // 30%宽度
        fileNameColumn.prefWidthProperty().bind(fatTable.widthProperty().multiply(0.3)); // 30%宽度

        // 禁止列重排序
        fatTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
    }
    // 更新 FAT 表的数据
    public static void updateFATTable() {
        if (fatTableEntries == null) return;

        // 在JavaFX应用程序线程中更新UI
        javafx.application.Platform.runLater(() -> {
            fatTableEntries.clear();

            // 更新FAT表显示
            for (int i = 0; i < 128; i++) {
                int status = getFATStatus(i);
                String fileType = getFileType(i);
                String fileName = getFileName(i);

                // 对于前三个系统保留块特殊处理
                if (i < 3) {
                    fileType = "系统";
                    fileName = "系统保留";
                }

                fatTableEntries.add(new FAT_tableEntry(i, status, fileType, fileName));
            }
        });
    }

    // 获取 FAT 表的状态
    public static int getFATStatus(int blockNumber) {
        if (blockNumber < 64) {
            byte status = DiskManage.readOnlyByte(0, blockNumber / 8, blockNumber % 8);
            // 如果状态是255（-1的无符号表示），则返回-1
            return (status & 0xFF) == 255 ? -1 : status & 0xFF;
        } else {
            byte status = DiskManage.readOnlyByte(1, (blockNumber - 64) / 8, (blockNumber - 64) % 8);
            // 如果状态是255（-1的无符号表示），则返回-1
            return (status & 0xFF) == 255 ? -1 : status & 0xFF;
        }
    }


    // 设置 FAT 表的状态
    public static void setFATStatus(int blockNumber, int status) {
        if (blockNumber < 64) {
            DiskManage.writeOnlyByte(0, blockNumber / 8, blockNumber % 8, (byte) status);
        } else {
            DiskManage.writeOnlyByte(1, (blockNumber - 64) / 8, (blockNumber - 64) % 8, (byte) status);
        }

        // 更新 TableView
        updateFATTable();
    }

    // 获取文件类型
    private static String getFileType(int blockNumber) {
        // 检查FAT表状态
        int status = getFATStatus(blockNumber);
        if (status == 0) {
            return "空闲";
        }

        if (blockNumber < 3) {
            return "系统";
        }

        // 首先检查是否是某个文件/文件夹的起始块
        Directory_Node node = findNodeByStartBlock(DirectoryTreeBuilder.rootDirectory_Node, blockNumber);
        if (node != null) {
            return (node.getAttribute() == 8) ? "文件夹" : "文件";
        }

        // 如果不是起始块，检查是否为文件的后续块
        node = findNodeContainingBlock(DirectoryTreeBuilder.rootDirectory_Node, blockNumber);
        if (node != null) {
            return (node.getAttribute() == 8) ? "文件夹" : "文件";
        }

        return "已占用";
    }

    // 获取文件名字
    private static String getFileName(int blockNumber) {
        // 检查FAT表状态
        int status = getFATStatus(blockNumber);
        if (status == 0) {
            return "未使用";
        }

        // 遍历所有目录查找该块的文件名
        Directory_Node node = findNodeByStartBlock(DirectoryTreeBuilder.rootDirectory_Node, blockNumber);
        if (node != null) {
            return new String(node.getFile_Name()).trim();
        }

        // 如果没有直接找到，检查是否为文件的后续块
        node = findNodeContainingBlock(DirectoryTreeBuilder.rootDirectory_Node, blockNumber);
        if (node != null) {
            return new String(node.getFile_Name()).trim();
        }

        return "系统块";
    }

    // 新增方法：查找以指定块号开始的节点
    private static Directory_Node findNodeByStartBlock(Directory_Node root, int blockNumber) {
        if (root == null) {
            return null;
        }

        // 检查当前节点
        if (root.getStartBlock() == blockNumber) {
            return root;
        }

        // 递归检查子节点
        if (root.getChildrens() != null) {
            for (Directory_Node child : root.getChildrens()) {
                Directory_Node result = findNodeByStartBlock(child, blockNumber);
                if (result != null) {
                    return result;
                }
            }
        }

        return null;
    }

    // 新增方法：查找包含指定块号的文件节点
    private static Directory_Node findNodeContainingBlock(Directory_Node root, int blockNumber) {
        if (root == null) {
            return null;
        }

        // 检查当前节点是否为文件，且其块链包含目标块号
        if (root.getAttribute() != 8) { // 不是目录
            int currentBlock = root.getStartBlock();
            while (currentBlock != -1) {
                if (currentBlock == blockNumber) {
                    return root;
                }
                currentBlock = getFATStatus(currentBlock);
            }
        }

        // 递归检查子节点
        if (root.getChildrens() != null) {
            for (Directory_Node child : root.getChildrens()) {
                Directory_Node result = findNodeContainingBlock(child, blockNumber);
                if (result != null) {
                    return result;
                }
            }
        }

        return null;
    }

    // 添加新的辅助方法用于查找指定块号对应的节点
    private static Directory_Node findNodeByBlock(Directory_Node root, int blockNumber) {
        if (root == null) {
            return null;
        }

        // 检查当前节点
        if (root.getStartBlock() == blockNumber) {
            return root;
        }

        // 递归检查子节点
        if (root.getChildrens() != null) {
            for (Directory_Node child : root.getChildrens()) {
                Directory_Node result = findNodeByBlock(child, blockNumber);
                if (result != null) {
                    return result;
                }
            }
        }

        return null;
    }

}